[XEN] Fix the emulation of instructions in vm86 mode. It fetches
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Tue, 19 Sep 2006 10:13:10 +0000 (11:13 +0100)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Tue, 19 Sep 2006 10:13:10 +0000 (11:13 +0100)
them using cs and eip instead of only eip. This makes it at least
possible to use the i945GM vesa bios from the running system.

Signed-off-by: Bastian Blank <waldi@debian.org>
xen/arch/x86/traps.c

index 07486ddcddb4e3249727d4124a974d705367ba53..01f5526b806e87e0b8ee71f6f7e9f5d6d32467ed 100644 (file)
@@ -1028,9 +1028,11 @@ static inline unsigned char inb_user(
     (admin_io_okay(_p, 4, _d, _r) ? outl(_v, _p) : ((void)0))
 
 /* Instruction fetch with error handling. */
-#define insn_fetch(_type, _size, _ptr)                                      \
-({  unsigned long _rc, _x;                                                  \
-    if ( (_rc = copy_from_user(&_x, (_type *)eip, sizeof(_type))) != 0 )    \
+#define insn_fetch(_type, _size, cs, eip)                                   \
+({  unsigned long _rc, _x, _ptr = eip;                                      \
+    if ( vm86_mode(regs) )                                                  \
+        _ptr += cs << 4;                                                    \
+    if ( (_rc = copy_from_user(&_x, (_type *)_ptr, sizeof(_type))) != 0 )   \
     {                                                                       \
         propagate_page_fault(eip + sizeof(_type) - _rc, 0);                 \
         return EXCRET_fault_fixed;                                          \
@@ -1040,7 +1042,7 @@ static inline unsigned char inb_user(
 static int emulate_privileged_op(struct cpu_user_regs *regs)
 {
     struct vcpu *v = current;
-    unsigned long *reg, eip = regs->eip, res;
+    unsigned long *reg, eip = regs->eip, cs = regs->cs, res;
     u8 opcode, modrm_reg = 0, modrm_rm = 0, rep_prefix = 0;
     unsigned int port, i, op_bytes = 4, data, rc;
     u32 l, h;
@@ -1048,7 +1050,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
     /* Legacy prefixes. */
     for ( i = 0; i < 8; i++ )
     {
-        switch ( opcode = insn_fetch(u8, 1, eip) )
+        switch ( opcode = insn_fetch(u8, 1, cs, eip) )
         {
         case 0x66: /* operand-size override */
             op_bytes ^= 6; /* switch between 2/4 bytes */
@@ -1080,7 +1082,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
         modrm_rm  = (opcode & 1) << 3;  /* REX.B */
 
         /* REX.W and REX.X do not need to be decoded. */
-        opcode = insn_fetch(u8, 1, eip);
+        opcode = insn_fetch(u8, 1, cs, eip);
     }
 #endif
     
@@ -1162,7 +1164,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
     case 0xe4: /* IN imm8,%al */
         op_bytes = 1;
     case 0xe5: /* IN imm8,%eax */
-        port = insn_fetch(u8, 1, eip);
+        port = insn_fetch(u8, 1, cs, eip);
     exec_in:
         if ( !guest_io_okay(port, op_bytes, v, regs) )
             goto fail;
@@ -1191,7 +1193,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
     case 0xe6: /* OUT %al,imm8 */
         op_bytes = 1;
     case 0xe7: /* OUT %eax,imm8 */
-        port = insn_fetch(u8, 1, eip);
+        port = insn_fetch(u8, 1, cs, eip);
     exec_out:
         if ( !guest_io_okay(port, op_bytes, v, regs) )
             goto fail;
@@ -1240,7 +1242,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
         goto fail;
 
     /* Privileged (ring 0) instructions. */
-    opcode = insn_fetch(u8, 1, eip);
+    opcode = insn_fetch(u8, 1, cs, eip);
     switch ( opcode )
     {
     case 0x06: /* CLTS */
@@ -1258,7 +1260,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
         break;
 
     case 0x20: /* MOV CR?,<reg> */
-        opcode = insn_fetch(u8, 1, eip);
+        opcode = insn_fetch(u8, 1, cs, eip);
         modrm_reg |= (opcode >> 3) & 7;
         modrm_rm  |= (opcode >> 0) & 7;
         reg = decode_register(modrm_rm, regs, 0);
@@ -1292,7 +1294,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
         break;
 
     case 0x21: /* MOV DR?,<reg> */
-        opcode = insn_fetch(u8, 1, eip);
+        opcode = insn_fetch(u8, 1, cs, eip);
         modrm_reg |= (opcode >> 3) & 7;
         modrm_rm  |= (opcode >> 0) & 7;
         reg = decode_register(modrm_rm, regs, 0);
@@ -1302,7 +1304,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
         break;
 
     case 0x22: /* MOV <reg>,CR? */
-        opcode = insn_fetch(u8, 1, eip);
+        opcode = insn_fetch(u8, 1, cs, eip);
         modrm_reg |= (opcode >> 3) & 7;
         modrm_rm  |= (opcode >> 0) & 7;
         reg = decode_register(modrm_rm, regs, 0);
@@ -1342,7 +1344,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
         break;
 
     case 0x23: /* MOV <reg>,DR? */
-        opcode = insn_fetch(u8, 1, eip);
+        opcode = insn_fetch(u8, 1, cs, eip);
         modrm_reg |= (opcode >> 3) & 7;
         modrm_rm  |= (opcode >> 0) & 7;
         reg = decode_register(modrm_rm, regs, 0);